package com.psedu.base.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.psedu.base.constant.Constants;
import com.psedu.base.domain.*;
import com.psedu.base.domain.vo.SignRecordQueryVo;
import com.psedu.base.domain.vo.SignRecordVo;
import com.psedu.base.domain.vo.StudentPositionVo;
import com.psedu.base.domain.vo.UnSignStudentVo;
import com.psedu.base.mapper.*;
import com.psedu.common.core.constant.HttpStatus;
import com.psedu.common.core.constant.SecurityConstants;
import com.psedu.common.core.domain.R;
import com.psedu.common.core.exception.ServiceException;
import com.psedu.common.core.utils.DateUtils;
import com.psedu.common.security.utils.SecurityUtils;
import com.psedu.system.api.RemoteUserService;
import com.psedu.system.api.domain.SysUser;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.psedu.base.service.ISignRecordService;

/**
 * 签到记录Service业务层处理
 * 
 * @author mingyue
 * @date 2022-05-16
 */
@Service
public class SignRecordServiceImpl implements ISignRecordService 
{
    @Autowired
    private SignRecordMapper signRecordMapper;
    @Autowired
    private SignLaunchMapper signLaunchMapper;
    @Autowired
    private RemoteUserService remoteUserService;
    @Autowired
    private CourseMapper courseMapper;
    @Autowired
    private SemesterDeptMapper semesterDeptMapper;
    @Autowired
    private ApplyMapper applyMapper;

    private final static double EARTH_RADIUS = 6378.137;

    /**
     * 查询签到记录
     * 
     * @param signRecordId 签到记录主键
     * @return 签到记录
     */
    @Override
    public SignRecord selectSignRecordBySignRecordId(Long signRecordId)
    {
        return signRecordMapper.selectSignRecordBySignRecordId(signRecordId);
    }

    /**
     * 查询签到记录列表
     * 
     * @param signRecord 签到记录
     * @return 签到记录
     */
    @Override
    public List<SignRecordVo> selectSignRecordList(SignRecordQueryVo signRecord)
    {
        List<SignRecord> signRecords = signRecordMapper.selectSignRecordList(signRecord);
        List<Long> userIds = signRecords.stream().map(SignRecord::getPseduUserId).collect(Collectors.toList());
        R<Map<Long, SysUser>> userInfoR = remoteUserService.getUserInfo(userIds, SecurityConstants.INNER);
        Map<Long, SysUser> userInfoMap = userInfoR.getData();
        List<SignRecordVo> signRecordVos = signRecords.stream().map(nowSignRecord -> {
            SignRecordVo signRecordVo = new SignRecordVo();
            BeanUtils.copyProperties(nowSignRecord, signRecordVo);
            // 填充学生姓名
            Long pseduUserId = nowSignRecord.getPseduUserId();
            SysUser sysUser = userInfoMap.get(pseduUserId);
            if(sysUser != null) {
                signRecordVo.setNickName(sysUser.getNickName());
            }
            return signRecordVo;
        }).collect(Collectors.toList());

        return signRecordVos;
    }

    /**
     * 新增签到记录
     * 
     * @param signRecord 签到记录
     * @return 结果
     */
    @Override
    public int insertSignRecord(SignRecord signRecord)
    {
        signRecord.setCreateTime(DateUtils.getNowDate());
        return signRecordMapper.insertSignRecord(signRecord);
    }

    /**
     * 修改签到记录
     * 
     * @param signRecord 签到记录
     * @return 结果
     */
    @Override
    public int updateSignRecord(SignRecord signRecord)
    {
        return signRecordMapper.updateSignRecord(signRecord);
    }

    /**
     * 批量删除签到记录
     * 
     * @param signRecordIds 需要删除的签到记录主键
     * @return 结果
     */
    @Override
    public int deleteSignRecordBySignRecordIds(Long[] signRecordIds)
    {
        return signRecordMapper.deleteSignRecordBySignRecordIds(signRecordIds);
    }

    /**
     * 删除签到记录信息
     * 
     * @param signRecordId 签到记录主键
     * @return 结果
     */
    @Override
    public int deleteSignRecordBySignRecordId(Long signRecordId)
    {
        return signRecordMapper.deleteSignRecordBySignRecordId(signRecordId);
    }

    @Override
    public void studentSign(Long userId, Long signLaunchId, StudentPositionVo studentPositionVo) {
        SignLaunch signLaunch = signLaunchMapper.selectById(signLaunchId);
        // 是否已经签到
        List<SignRecord> signRecords = signRecordMapper.selectList(
                new LambdaQueryWrapper<SignRecord>()
                        .eq(SignRecord::getSignLaunchId, signLaunchId)
                        .eq(SignRecord::getPseduUserId, userId)
        );
        if(CollectionUtil.isNotEmpty(signRecords)) {
            throw new ServiceException("您已签到", HttpStatus.BAD_REQUEST);
        }
        // 签到规定信息
        Date startTime = signLaunch.getStartTime();
        Date endTime = signLaunch.getEndTime();
        // 在时间内
        Date nowDate = new Date();
        if(nowDate.before(startTime)) {
            throw new ServiceException("签到未开始", HttpStatus.BAD_REQUEST);
        } else if(nowDate.after(endTime)) {
            throw new ServiceException("签到已经结束", HttpStatus.BAD_REQUEST);
        }
        // 签到规定信息
        Double centerLatitude = signLaunch.getLatitude();
        Double centerLongitude = signLaunch.getLongitude();
        Double accuracy = signLaunch.getAccuracy();
        if(centerLatitude == null || centerLongitude ==  null || accuracy == null) {
            SignRecord signRecord = new SignRecord();
            signRecord.setPseduUserId(userId);
            signRecord.setLongitude(studentPositionVo.getLng());
            signRecord.setLatitude(studentPositionVo.getLat());
            signRecord.setSignLaunchId(signLaunchId);
            signRecordMapper.insert(signRecord);
            return ;
        }
        double realDistance = getDistance(centerLongitude,centerLatitude,studentPositionVo.getLng(),studentPositionVo.getLat());
        if(realDistance <= accuracy * 5) {
            SignRecord signRecord = new SignRecord();
            signRecord.setPseduUserId(userId);
            signRecord.setLongitude(studentPositionVo.getLng());
            signRecord.setLatitude(studentPositionVo.getLat());
            signRecord.setSignLaunchId(signLaunchId);
            signRecord.setAccuracy(realDistance);
            signRecordMapper.insert(signRecord);
        } else {
            throw new ServiceException("签到失败，您不在签到范围内", HttpStatus.BAD_REQUEST);
        }


    }

    @Override
    public List<UnSignStudentVo> selectUnSignStudentList(SignRecordQueryVo signRecordQueryVo) {
        // courseId 看本次课程部门（+合班），courseId对应课程，获取到dept和merge_class、seme_id
        Course course = courseMapper.selectById(signRecordQueryVo.getCourseId());
        // 如果有部门，就只要本学期本部门的，如果是merge_class则找出本学期合班内的所有部门(学期部门表获取)
        List<Long> deptList = new ArrayList<>();
        Long courseLimitDeptId = course.getDeptId();
        if(courseLimitDeptId != null && courseLimitDeptId != 0) {
            deptList.add(courseLimitDeptId);
        } else {
            // 获取该学期合班下的所有部门
            List<SemesterDept> semesterDepts = semesterDeptMapper.selectList(
                    new LambdaQueryWrapper<SemesterDept>()
                            .eq(SemesterDept::getMergeClassId, course.getMergeClassId())
                            .eq(SemesterDept::getSemeId, course.getMergeClassId())
            );
            deptList = semesterDepts.stream().map(SemesterDept::getDeptId).collect(Collectors.toList());
        }
        // dept部门本学期内的所有student名单，not in 排除掉已经签到的
        // 已经签到的
        List<SignLaunch> signLaunches = signLaunchMapper.selectList(
                new LambdaQueryWrapper<SignLaunch>()
                        .eq(SignLaunch::getCourseId, course.getCourseId())
        );
        if(CollectionUtil.isEmpty(signLaunches)) {
            throw new ServiceException("不存在该签到场次", HttpStatus.BAD_REQUEST);
        }
        SignLaunch signLaunch = signLaunches.get(0);
        List<SignRecord> signRecords = signRecordMapper.selectList(
                new LambdaQueryWrapper<SignRecord>()
                        .eq(SignRecord::getSignLaunchId, signLaunch.getSignLaunchId())
        );
        List<Long> signUserIdList = signRecords.stream().map(SignRecord::getPseduUserId).collect(Collectors.toList());
        LambdaQueryWrapper<Apply> applyLambdaQueryWrapper = new LambdaQueryWrapper<Apply>()
                .eq(Apply::getChecked, Constants.APPLY_PASS)
                .eq(Apply::getSemeId, course.getSemeId())
                .in(Apply::getDeptId, deptList);
        if(signUserIdList.size() != 0) {
            applyLambdaQueryWrapper.notIn(Apply::getPsUserId, signUserIdList);
        }
        List<Apply> notSignStudentList = applyMapper.selectList(
                applyLambdaQueryWrapper
        );
        List<UnSignStudentVo> unSignStudentList = notSignStudentList.stream().map(apply -> {
            UnSignStudentVo unSignStudentVo = new UnSignStudentVo();
            unSignStudentVo.setHnusterId(apply.getHnusterId());
            unSignStudentVo.setPsUserId(apply.getPsUserId());
            unSignStudentVo.setNickName(apply.getRealName());
            return unSignStudentVo;
        }).collect(Collectors.toList());
        return unSignStudentList;
    }

    /**
     * @param lng1: A点的经度
     * @param lat1: A点的纬度
     * @param lng2: B点的经度
     * @param lat2: B点的纬度
     * @return 返回距离 单位：米
     */
    private double getDistance(double lng1,double lat1,double lng2,double lat2) {
        double lngA = (lng1 * Math.PI / 180.0);
        double latA = (lat1 * Math.PI / 180.0);
        double lngB = (lng2 * Math.PI / 180.0);
        double latB = (lat2 * Math.PI / 180.0);
        double a = latA - latB;
        double b = lngA - lngB;
        double s = 2 * Math.sin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(latA) * Math.cos(latB) * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        return s * 1000;
    }
}
